/*
 * Copyright (c) 2025 Li Auto Inc. and its affiliates
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <discovery/database/DiscoverySharedInfo.hpp>
#include <discovery/database/DiscoveryEndpointInfo.hpp>

#include <ertps/utils/fixed_size_string.hpp>

#include <history/CacheChange.h>
#include <edds/rtps/common/GuidPrefix_t.hpp>

#include <nlohmann/json.hpp>

#include <xmlparser/qos/XMLReaderQos.hpp>
#include <xmlparser/qos/XMLWriterQos.hpp>
namespace evbs {
namespace ertps {
namespace rtps {
namespace ddb {
const std::string DiscoveryEndpointInfo::topic() const {
    return topic_;
}

void DiscoveryEndpointInfo::is_virtual(bool is_virtual) {
    is_virtual_ = is_virtual;
}

bool DiscoveryEndpointInfo::is_virtual() const {
    return is_virtual_;
}

void DiscoveryEndpointInfo::is_rpc(bool is_rpc) {
    is_rpc_ = is_rpc;
}

bool DiscoveryEndpointInfo::is_rpc() const {
    return is_rpc_;
}

void DiscoveryEndpointInfo::to_json(nlohmann::json& j) const {
    DiscoverySharedInfo::to_json(j);
    j["topic"] = topic_;
    j["type"] = type_name_;
    j["take_locator"] = take_locator_;
    j["queue_id"] = dsf_queue_id;
}

void DiscoveryEndpointInfo::set_qos(EndpointQos& qos) {
    qos_ = qos;
}

EndpointQos DiscoveryEndpointInfo::get_qos() const {
    return qos_;
}

bool DiscoveryEndpointInfo::take_locator() const {
    return take_locator_;
}

void DiscoveryEndpointInfo::take_locator(bool take_locator) {
    take_locator_ = take_locator;
}

uint32_t DiscoveryEndpointInfo::get_queue_id() const {
    return dsf_queue_id;
}

void DiscoveryEndpointInfo::set_queue_id(uint32_t queue_id) {
    dsf_queue_id = queue_id;
}

bool DiscoveryEndpointInfo::is_authenticated_writers(GuidPrefix_t writer_guid) const {
    return authenticated_writers_.find(writer_guid) != authenticated_writers_.end();
}

void DiscoveryEndpointInfo::insert_authenticated_writers(GuidPrefix_t writer_guid) {
    authenticated_writers_.insert(writer_guid);
}

void DiscoveryEndpointInfo::remove_authenticated_writers(GuidPrefix_t writer_guid) {
    (void)authenticated_writers_.erase(writer_guid);
}

bool DiscoveryEndpointInfo::valid_matching(DiscoveryEndpointInfo& winfo, const GUID_t& writer_guid,
                                           DiscoveryEndpointInfo& rinfo, const GUID_t& reader_guid) {
    bool ret = true;
    if (winfo.is_virtual() || rinfo.is_virtual() || winfo.is_rpc() || rinfo.is_rpc()) {
        return ret;
    }

    if ((winfo.get_qos().m_reliability.kind == vbsutil::xmlparser::BEST_EFFORT_RELIABILITY_QOS) &&
        (rinfo.get_qos().m_reliability.kind == vbsutil::xmlparser::RELIABLE_RELIABILITY_QOS))
    // Means our writer is BE but the reader wants RE
    {
        elogError(DISCOVERY_DATABASE, RetCode_t::RETCODE_INCONSISTENT_POLICY,
                  "INCOMPATIBLE QOS (topic: " << topic() << "): Reader " << reader_guid << " is Reliable and Writer "
                                              << writer_guid << " is BE ");
        ret = false;
    }

    if (winfo.get_qos().m_durability.kind < rinfo.get_qos().m_durability.kind) {
        // TODO (MCC) Change log message
        elogError(DISCOVERY_DATABASE, RetCode_t::RETCODE_INCONSISTENT_POLICY,
                  "INCOMPATIBLE QOS (topic: " << topic() << "):Reader " << reader_guid
                                              << " has TRANSIENT_LOCAL DURABILITY and Writer " << writer_guid
                                              << " offer VOLATILE");
        ret = false;
    }

    if (winfo.get_qos().m_ownership.kind != rinfo.get_qos().m_ownership.kind) {
        elogError(DISCOVERY_DATABASE, RetCode_t::RETCODE_INCONSISTENT_POLICY,
                  "INCOMPATIBLE QOS (topic: " << topic() << "):Reader " << reader_guid
                                              << " has different Ownership Kind with Writer " << writer_guid);
        ret = false;
    }

    if (winfo.get_qos().m_deadline.period > rinfo.get_qos().m_deadline.period) {
        elogError(DISCOVERY_DATABASE, RetCode_t::RETCODE_INCONSISTENT_POLICY,
                  "INCOMPATIBLE QOS (topic: " << topic() << "):Reader " << reader_guid
                                              << " has smaller DEADLINE period than Writer " << writer_guid << " ("
                                              << winfo.get_qos().m_deadline.period << " > "
                                              << rinfo.get_qos().m_deadline.period << ")");
        ret = false;
    }

    if (winfo.get_qos().m_liveliness.lease_duration > rinfo.get_qos().m_liveliness.lease_duration) {
        elogError(DISCOVERY_DATABASE, RetCode_t::RETCODE_INCONSISTENT_POLICY,
                  "(topic: " << topic() << ") Incompatible liveliness lease durations: Writer " << writer_guid
                             << " offered lease duration " << winfo.get_qos().m_liveliness.lease_duration
                             << " must be <= requested lease duration " << rinfo.get_qos().m_liveliness.lease_duration
                             << " of Reader " << reader_guid);
        ret = false;
    }

    if (winfo.get_qos().m_liveliness.kind < rinfo.get_qos().m_liveliness.kind) {
        elogError(DISCOVERY_DATABASE, RetCode_t::RETCODE_INCONSISTENT_POLICY,
                  "(topic: " << topic() << ") Incompatible liveliness kinds: Writer " << writer_guid
                             << " offered kind is < requested kind of Reader " << reader_guid);
        ret = false;
    }

    if (rinfo.get_qos().m_e2eProtecion.needCheckEnableFlag || winfo.get_qos().m_e2eProtecion.needCheckEnableFlag) {
        if (winfo.get_qos().m_e2eProtecion.enabled != rinfo.get_qos().m_e2eProtecion.enabled) {
            elogError(DISCOVERY_DATABASE, RetCode_t::RETCODE_INCONSISTENT_POLICY,
                      "(topic: " << topic() << ") INCOMPATIBLE QOS m_e2eProtecion check err, Writer " << writer_guid
                                 << " e2eProtecion flag = " << winfo.get_qos().m_e2eProtecion.enabled << ", Reader "
                                 << reader_guid << " e2eProtecion flag= " << rinfo.get_qos().m_e2eProtecion.enabled);
            return false;
        }
    }

    return ret;
}

} /* namespace ddb */
} /* namespace rtps */
} /* namespace ertps */
} /* namespace evbs */
